package com.study.netty2;

import com.study.constant.Constants;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

/**
 * @author mjy
 * @date 2021/12/07
 * @description 1.创建两个工作线程组
 * 2.创建服务端启动对象，配置连接参数
 * 3.绑定端口号，启动Netty
 */

@Component
public class NettyServer {

    /**
     * 连接线程组
     */
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    /**
     * 工作线程组
     */
    private EventLoopGroup workGroup = new NioEventLoopGroup();


    public void start(InetSocketAddress address) {
        //创建服务端启动对象
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup)
                /**
                 *使用NioServerSocketChannel作为服务器的通道实现
                 */
                .channel(NioServerSocketChannel.class)
                /**
                 * 设置线程队列的连接数
                 */
                .option(ChannelOption.SO_BACKLOG, 1024)
                /**
                 * 通过NoDelay禁用Nagle,使消息立即发出去，不用等待到一定的数据量才发出去
                 */
                .childOption(ChannelOption.TCP_NODELAY, true)
                /**
                 * 给对应的workerGroup的EventLoop对应的管道设置处理器
                 */
                .childHandler(
                        new ChannelInitializer<Channel>() {
                            @Override
                            protected void initChannel(Channel ch) throws Exception {
                                /**
                                 *对每条消息以结尾标识符切分，认为这是一组数据
                                 */
                                ByteBuf buf = Unpooled.copiedBuffer(Constants.MESSAGE_SUFFIX.getBytes());
                                ch.pipeline().addLast(new DelimiterBasedFrameDecoder(819200, buf));
                                ch.pipeline().addLast("decode", new StringDecoder());
                                ch.pipeline().addLast("encode", new MessageEncode());
                                //经过编码解码处理后，收到的bytebuf已经变成自己的bean了，
                                // 这个handler的先后顺序有讲究的，除非把资源释放，后面的handler才能拿到
                                ch.pipeline().addLast(new ServerIdHandler());
                                //处理通讯
                                ch.pipeline().addLast(new ServerHandler());
                            }
                        }
                );
        //绑定端口，开始接收进来的连接
        try {
            ChannelFuture sync = bootstrap.bind(address).sync();
            if (sync.isSuccess()) {
                System.out.println("启动 Netty 成功");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            //异常关闭连接组线程和工作组线程
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }

    }

    /**
     * 在服务卸载的时候依旧关闭线程组
     */

    public void destory() {
        bossGroup.shutdownGracefully();
        workGroup.shutdownGracefully();
        System.out.println("关闭Netty成功");
    }


}
